//******************************************************************/
//MCU SD卡SD模式控制接口
//V0.1		2014-09-20		yshao	
//V0.2		2018-11-29		yshao	
//******************************************************************/
`timescale	1ps/1ps
module mcu_sd_cnt(
		input	wire		resetb,
                input	wire		sclk,
                
		input	wire		mcu_sd_en,
		
		input	wire		mcu_spi_clk,
		input	wire		mcu_spi_mosi,
		output	reg		mcu_spi_miso,
		
		input	wire		mcu_fpga_ctrl,
                
		output	reg		sd_clk,
		output	wire		sd_cmd_oe,
		output	reg		sd_cmd_out,
		input	wire		sd_cmd_in,
		output	wire		sd_dat_oe,
		output	wire	[3:0]	sd_dat_out,
		input	wire	[3:0]	sd_dat_in,
		
		output	wire	[15:0]	tout
		);

reg		mcu_mosi, sd_cmd_en, read_cmd;
reg	[3:0]	sd_din, sd_din_t;
reg	[5:0]	mosi_shift;
reg	[5:0]	cmd_clk_count;
reg		clk_stop, block_tran_mask;
reg		crc_calc_en, crc_out_en;
reg	[6:0]	crc_data;
reg		rec_count_en, rec_load, data_rec_en, data_out_en;
reg	[2:0]	rec_count, out_count;
reg	[7:0]	rec_shift, sd_rec_data, out_shift;
reg	[10:0]	data_rec_count;
reg	[12:0]	data_out_count;
reg		out_start_bit, ooo_t, data_out_start;
wire		data_rec_end, data_out_end, sd_buf_out, mcu_sd_rd;
reg		sd_cin, sd_ddd_out, crc_out, out_load, mcu_sd_rd_rst;
//**************************************************************
//		接收数据沿变换
//**************************************************************
//单片机MOSI数据沿变换
always	@(posedge mcu_spi_clk)
	mcu_mosi <= mcu_spi_mosi;

//单片机MOSI数据沿变换
always	@(posedge mcu_spi_clk)
	sd_cin <= sd_cmd_in;

//SD卡DAT数据沿变换
always	@(posedge mcu_spi_clk)
	sd_din <= sd_dat_in;

//**************************************************************
//		SD模式MCU MOSI 检测
//**************************************************************
//SD模式MOSI命令传输使能
always @(mcu_sd_en or mcu_sd_rd)
	if (mcu_sd_en == 1 && mcu_sd_rd == 0)
		sd_cmd_en <= 1'b1;
	else
		sd_cmd_en <= 1'b0;

//MCU输入串移
always	@(negedge mcu_spi_clk)
	mosi_shift <= {mosi_shift[4:0], mcu_spi_mosi};

//***************SD模式CMD命令检测*******************
//CMD命令bit计数
always	@(negedge mcu_spi_clk or negedge sd_cmd_en)
	if (sd_cmd_en == 0)
		cmd_clk_count <= 0;
	else
		cmd_clk_count <= cmd_clk_count + 1;
	
//CMD17命令标识
always	@(negedge mcu_spi_clk)
	if (cmd_clk_count == 9)
		if (mosi_shift[5:0] == 6'h11 || mosi_shift[5:0] == 6'h12)
			read_cmd <= 1;
		else
			read_cmd <= 0;

//**************************************************************
//		给SD卡的clk信号
//**************************************************************
always	@(negedge mcu_spi_clk or negedge mcu_sd_rd_rst)
	if (mcu_sd_rd_rst == 0)
		clk_stop <= 0;
	else if (data_out_en == 1 && data_rec_en == 0)
		clk_stop <= 1;
	else
		clk_stop <= 0;

always	@(posedge mcu_spi_clk or negedge mcu_sd_rd_rst)
	if (mcu_sd_rd_rst == 0)
		block_tran_mask <= 0;
	else
		block_tran_mask <= clk_stop;

always @(mcu_sd_en or block_tran_mask or mcu_spi_clk)
	if (mcu_sd_en == 0)
		sd_clk <= 1'b1;
	else if (block_tran_mask == 1)
		sd_clk <= 1'b1;
	else
		sd_clk <= mcu_spi_clk;

//**************************************************************
//		给SD卡的CMD信号
//**************************************************************
//*******************SD模式CRC7*******************
always	@(negedge mcu_spi_clk or negedge sd_cmd_en)
	if (sd_cmd_en == 0)
		crc_calc_en <= 0;
	else
		crc_calc_en <= 1;

always	@(negedge mcu_spi_clk or negedge crc_calc_en)
	if (crc_calc_en == 0)
		crc_out_en <= 0;
	else if(cmd_clk_count >= 40)
		crc_out_en <= 1;
	
always	@(negedge mcu_spi_clk or negedge crc_calc_en)
	if (crc_calc_en == 0)
		crc_data <= 0;
	else if(crc_out_en == 1)
		crc_data <= {crc_data[5:0], 1'b1};
	else if(crc_data[6] != mcu_mosi)
		crc_data <= {crc_data[5:0], 1'b0} ^ 7'b0001001;
	else
		crc_data <= {crc_data[5:0], 1'b0};
		
//*******************CMD输出选择*******************
always @(mcu_sd_en or mcu_sd_rd or crc_out_en or crc_out or mcu_spi_mosi)
	if (mcu_sd_en == 0 || mcu_sd_rd == 1)
		sd_cmd_out <= 1;
	else if (crc_out_en == 1)
		sd_cmd_out <= crc_data[6];
	else
		sd_cmd_out <= mcu_spi_mosi;

//****************SD模式cmd输出使能****************
assign	sd_cmd_oe = sd_cmd_en;		
assign	mcu_sd_rd = mcu_fpga_ctrl;

always@(posedge sclk)
	if (mcu_sd_en == 1)
		mcu_sd_rd_rst <= mcu_fpga_ctrl;
	else
		mcu_sd_rd_rst <= 0;

//**************************************************************
//		给SD卡的DAT信号
//**************************************************************
assign	sd_dat_oe = 1'h0;
assign	sd_dat_out = 4'h0;

//**************************************************************
//		给MCU的MISO信号
//**************************************************************
//返回给MCU的MISO信号
always @(mcu_sd_en or sd_dat_in or out_start_bit or data_out_en or sd_ddd_out or out_shift)
	if (mcu_sd_en == 0)
		mcu_spi_miso <= 1;		//不使能SD卡
	else if (out_start_bit == 1)
		mcu_spi_miso <= 1'b0;		//dat起始
	else if (data_out_en == 1)
		mcu_spi_miso <= sd_ddd_out;	//dat数据
	else
		mcu_spi_miso <= out_shift[0];	//response数据

//*******************SD模式response数据返回*******************
//CMD接收反馈串移
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		rec_shift <= 8'hFF;
	else
		rec_shift <= {sd_cin, rec_shift[7:1]};

//CMD接收反馈计数使能
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		rec_count_en <= 0;
	else if (rec_shift[7:6] == 2'b00)
		rec_count_en <= 1;
	
//CMD接收反馈计数
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		rec_count <= 0;
	else if (rec_count_en == 1)
		rec_count <= rec_count + 1;

//CMD接收反馈加载使能
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		rec_load <= 0;
	else if (rec_count == 4)
		rec_load <= 1;
	else
		rec_load <= 0;

//CMD接收反馈并行加载
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		sd_rec_data <= 8'hFF;
	else if (rec_load == 1)
		sd_rec_data <= rec_shift;

//SPI接口时钟计数
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		out_count <= 0;
	else
		out_count <= out_count + 1;

//SPI接口输出同步
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		out_load <= 0;
	else if(out_count == 7)
		out_load <= 1;
	else
		out_load <= 0;

//SPI接口输出
always	@(negedge mcu_spi_clk or posedge sd_cmd_en)
	if (sd_cmd_en == 1)
		out_shift <= 8'hFF;
	else if(out_load == 1)
		out_shift <= sd_rec_data;
	else
		out_shift <= {1'b1, out_shift[7:1]};

//*******************SD模式dat数据返回*******************
always	@(negedge mcu_spi_clk)
	sd_din_t <= sd_din;
	
always	@(negedge mcu_spi_clk)
	if (mcu_sd_en ==0 || mcu_sd_rd == 0 || read_cmd == 0)
		data_rec_en <= 0;
	else if (sd_din_t == 4'b0)
		data_rec_en <= 1;
	else if (data_rec_end == 1)
		data_rec_en <= 0;
	

//always	@(negedge mcu_spi_clk)
//	if (mcu_sd_en ==1 && mcu_sd_rd == 1 && read_cmd == 1 && sd_din_t == 4'b0)
//		data_rec_en <= 1;
//	else if (data_rec_end == 1)
//		data_rec_en <= 0;
	
always	@(negedge mcu_spi_clk)
	if (data_rec_en == 0)
		data_rec_count <= 0;
	else if (data_rec_end == 0)
		data_rec_count <= data_rec_count + 1;

assign	data_rec_end = data_rec_count[10] & data_rec_count[4];

sd_swsr_1kw4_4kr1_dp sd_buf (
		.data(sd_din_t),
		.wraddress(data_rec_count),
		.wrclock(~mcu_spi_clk),
		.wren(data_rec_en),
		.rdaddress({data_out_count[12:2], ~data_out_count[1], ~data_out_count[0]}),
		.rdclock(~mcu_spi_clk),
		.q(sd_buf_out));

always	@(negedge mcu_spi_clk)
	sd_ddd_out <= sd_buf_out;
	
always	@(negedge mcu_spi_clk)
	if (data_rec_en == 1 && data_out_en == 0 && out_count == 6)
		data_out_start <= 1;
	else
		data_out_start <= 0;
	
always	@(negedge mcu_spi_clk)
	out_start_bit <= data_out_start;

always	@(negedge mcu_spi_clk)
	if (mcu_sd_en == 0 || mcu_sd_rd == 0 || read_cmd == 0)
		data_out_en <= 0;
	else if (data_out_start == 1)
		data_out_en <= 1;
	else if (data_out_end == 1)
		data_out_en <= 0;
	
//always	@(negedge mcu_spi_clk)
//	if (read_cmd == 1 && data_out_start == 1)
//		data_out_en <= 1;
//	else if (data_out_end == 1)
//		data_out_en <= 0;
	
always	@(negedge mcu_spi_clk)
	if (data_out_en == 0)
		data_out_count <= 0;
	else if (data_out_end == 0)
		data_out_count <= data_out_count + 1;

assign	data_out_end = data_out_count[12];

//**************************************************************
//		测试信号输出
//**************************************************************
assign	tout = {16'h0};

endmodule